package com.carlinfo.common.dao.impl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.carlinfo.common.dao.IBaseDao;
import com.carlinfo.common.util.DbUtil;
import com.carlinfo.common.util.PageInfoUtil;

public abstract class BaseDaoImpl<T> implements IBaseDao<T>
{
	protected Logger logger = LogManager.getLogger();
	/* pojo的指定类型 */
	protected Object pojoObj;

	/**
	 * 查询一条记录
	 * 
	 * @param sql        有占位符
	 * @param paramsList 占位符对应的值
	 * @return
	 */
	protected T findOneJDBC(String sql, List<Object> paramsList)
	{
		/* 加载驱动+获取链接 */
		DbUtil dbUtil = DbUtil.getInstance();
		Connection conn = dbUtil.getConn();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try
		{
			this.logger.info("sql:{},paramList:{}",sql,paramsList);
			pst = conn.prepareStatement(sql);
			int count = 1;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object val = (Object) iterator.next();
				pst.setObject(count, val);
				count++;
			}
			rs = pst.executeQuery();
			if (rs.next())
			{
				T t = converFromDb(rs);
				return t;
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(conn, pst, rs);
		}

		return null;
	}

	/**
	 * @param pageInfoUtil 分页对象
	 * @param sql          sql语句:只有sql语句和占位符
	 * @param paramsList   占位符对应的值
	 * @return 查询的记录
	 */
	protected List<T> findListByPage(PageInfoUtil pageInfoUtil, String sql, List<Object> paramsList)
	{

		List<T> resultList = new ArrayList<T>();
		/*
		 * 写?的时候想想如何赋值 从PageInfo中获取---(传参)
		 */

		/* JDBC查询多条记录 */
		DbUtil dbUtil = DbUtil.getInstance();
		Connection conn = dbUtil.getConn();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try
		{
			int count = 1;
			if (pageInfoUtil != null)
			{
				String fromIndex = "from";
				String countSQL = "select count(*) " + sql.substring(sql.indexOf(fromIndex), sql.length());
				this.logger.info("countSQL:{},参数:{}", countSQL, resultList);
				/* 获取sql语句对象 */
				pst = conn.prepareStatement(countSQL);
				/* 为占位符赋值 */
				count = 1;
				for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
				{
					Object val = (Object) iterator.next();
					pst.setObject(count, val);
					count++;

				}
				/* 执行sql语句 */
				rs = pst.executeQuery();
				if (rs.next())
				{
					int totalRecord = rs.getInt(1);
					pageInfoUtil.setTotalRecord(totalRecord);
				}
				/* 关闭 */
				rs.close();
				pst.close();
				sql = sql + " limit ? , ? ";
				paramsList.add(pageInfoUtil.getCurrentRecord());
				paramsList.add(pageInfoUtil.getPageSize());
			}
			return this.findList(sql, paramsList);
		} catch (SQLException e)
		{
			logger.error("查询多条记录失败", e);
		} finally
		{
			dbUtil.closeAll(conn, pst, rs);
		}
		/* 比返回null强.不会报空指针 */
		return Collections.emptyList();

	}

	/**
	 * 查询多条记录,不分页
	 * 
	 * @param sql
	 * @param paramsList
	 * @return
	 */
	protected List<T> findList(String sql, List<Object> paramsList)
	{

		List<T> resultList = new ArrayList<T>();
		/*
		 * 写?的时候想想如何赋值 从PageInfo中获取---(传参)
		 */

		/* JDBC查询多条朝代 */
		DbUtil dbUtil = DbUtil.getInstance();
		Connection conn = dbUtil.getConn();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try
		{
			int count = 1;
			this.logger.info("sql:{},参数:{}", sql, paramsList);
			pst = conn.prepareStatement(sql);
			count = 1;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object val = (Object) iterator.next();
				pst.setObject(count, val);
				count++;
			}
			rs = pst.executeQuery();
			/*
			 * 如果是查询一条,用if 如果是查询多条用while
			 */
			while (rs.next())
			{
				T t = this.converFromDb(rs);
				resultList.add(t);
			}
			/* 将集合返回 */
			return resultList;
		} catch (SQLException e)
		{
			logger.error("查询多条记录失败", e);
		} finally
		{
			dbUtil.closeAll(conn, pst, rs);
		}
		/* 比返回null强.不会报空指针 */
		return Collections.emptyList();
	}

	/**
	 * CUD
	 * 
	 * @return 此sql语句影响的条数
	 */
	protected int executeJDBC(String sql, List<Object> paramsList)
	{
		/*
		 * JDBC的更新 先写JDBC的架子 加载驱动+ 获取链接
		 */
		DbUtil dbUtil = DbUtil.getInstance();
		Connection conn = dbUtil.getConn();
		PreparedStatement pst = null;

		try
		{
			this.logger.info("sql:{},paramList:{}", sql, paramsList);
			/* 准备sql语句对象 */
			pst = conn.prepareStatement(sql);
			int count = 1;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object val = (Object) iterator.next();
				pst.setObject(count, val);
				count++;
			}
			/* 执行sql语句 */
			int res = pst.executeUpdate();
			/* 一定要返回 */
			return res;
		} catch (SQLException e)
		{
			// e.printStackTrace();
			this.logger.error("朝代删除失败了", e);
		} finally
		{
			dbUtil.closeAll(conn, pst, null);
		}
		return 0;

	}

	/**
	 * CUD
	 * 
	 * @return 此条sql语句影响的条数
	 */
	protected int executeJDBC(String sql, List<Object> paramsList, Map<String, Object> resultMap)
	{
		/*
		 * JDBC的更新 先写JDBC的架子 加载驱动+ 获取链接
		 */
		DbUtil dbUtil = DbUtil.getInstance();
		Connection conn = dbUtil.getConn();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try
		{
			this.logger.info("sql:{},paramList:{}", sql, paramsList);
			/* 准备sql语句对象 */
			pst = conn.prepareStatement(sql);
			int count = 1;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object val = (Object) iterator.next();
				pst.setObject(count, val);
				count++;
			}
			/* 执行sql语句 */
			int res = pst.executeUpdate();
			rs = pst.getGeneratedKeys();
			if (rs.next())
			{
				/* 把主键放到了key中 */
				int id = rs.getInt(1);
				resultMap.put("id", id);
			}
			/* 一定要返回 */
			return res;
		} catch (SQLException e)
		{
			this.logger.error("朝代删除操作失败了;", e);
		} finally
		{
			dbUtil.closeAll(conn, pst, null);
		}
		return 0;
	}

	/**
	 * 将数据库里面的记录变成POJO
	 * 
	 * @param rs
	 * @return
	 */
	protected T converFromDb(ResultSet rs) throws SQLException
	{
		try
		{
			/*
			 * --列出pojo中所有的属性 获取Class对象 改包名咋办--
			 */
			/* Class.forName("com.carlinfo.demo.pojo.ADynasty"); */
			Class cla = pojoObj.getClass();
			/* new 对象 */
			T valObj = (T) cla.newInstance();
			/* 列出所有的属性 */
			Field[] allFields = cla.getDeclaredFields();
			for (int i = 0; i < allFields.length; i++)
			{
				Field field = allFields[i];
				try
				{
					String fileName = field.getName();
					if("byte".equalsIgnoreCase(field.getType().getName())
							||"int".equalsIgnoreCase(field.getType().getName())
							||"double".equalsIgnoreCase(field.getType().getName())
							||String.class.getName().equalsIgnoreCase(field.getType().getName())
							||Date.class.getName().equalsIgnoreCase(field.getType().getName()))
					{
						/* 要设置值 */
					}else
					{
						continue;
					}
					/*
					 * 获取数据库的值 整数:是第几列 字符串:列的别名
					 */
					Object val = rs.getObject(fileName);
					/*
					 * 将此值设置到对象中 fileName:属性名 读写器:写:set属性名(属性名的首字母大写)
					 * 
					 */
					String setName = "set" + fileName.substring(0, 1).toUpperCase()
							+ fileName.substring(1, fileName.length());
					
					/*
					 * setMethod获取到对象方法 参数1:方法名 参数2形参 方法定义
					 * 
					 */
					Method setMethod = cla.getMethod(setName, field.getType());
					// this.logger.info("==name:{},val:{}==setName:{};class:{}",
					// field.getName(),val,setName,field.getType());
					/* 处理个别的代码 */
					if ("byte".equalsIgnoreCase(field.getType().getName()))
					{
						/* 说明是Byte类型 */
						setMethod.invoke(valObj, Byte.valueOf(val + ""));
					} else
					{
						setMethod.invoke(valObj, val);
					}
				}catch(Exception e)
				{
					this.logger.error("赋值失败", e);
				}
			}

			return valObj;
		} catch (Exception e)
		{
			this.logger.error("从数据库中赋值给对象失败了", e);
		}
		return null;
	}
}
